﻿/*   
    Copyright (C) 2009 Galaktika Corporation ZAO

    This file is a part of Galaktika.BusinessMonitor
 
    Galaktika.BusinessMonitor is a free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
      
    You should have received a copy of the GNU General Public License
    along with Galaktika.BusinessMonitor.  If not, see <http://www.gnu.org/licenses/>.
  
    If GPL v.3 is not suitable for your products or company,
    Galaktika Corp provides Galaktika.BusinessMonitor under a flexible commercial license
    designed to meet your specific usage and distribution requirements.
    If you have already obtained a commercial license from Galaktika Corp,
    you can use this file under those license terms.
*/

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Galaktika.BI.Silverlight.Services;
using Galaktika.BI.Silverlight.ClientApp.ViewModel;
using Galaktika.BI.Runtime.Services;
using Galaktika.BI.Extensibility.Dom.Dac;
using System.IO;
using System.Text;
using Galaktika.BI.Silverlight.ClientApp.View;

namespace Galaktika.BI.Silverlight.ClientApp
{
    public static class QueryExecutionManager
    {
        static QueryExecutionData vm;
        public static void Initialize(QueryExecutionData viewModel)
        {
            vm = viewModel;
            SyncDataService.BeforeCommandInvokeActions.Add(p => ProcessQueriesFromClient(p));
            SyncDataService.AfterCommandInvokeActions.Add((r, p) => ProcessQueriesFromServer(r, p));
        }

        public static bool IsInitialized
        {
            get
            {
                return false;
            }
        }

        //static Dictionary<string, InvokeSchema> m_Queries = new Dictionary<string,InvokeSchema>();

        static void AppendQueryCommand(string id, InvokeSchema querySchema)
        {
            //lock (m_Queries)
            //{
            //    m_Queries.Add(id, querySchema);
            //}

            var data = CreateData(querySchema);
            Deployment.Current.Dispatcher.BeginInvoke(() => vm.Insert(0, data));
        }

        static QueryData CreateData(InvokeSchema querySchema)
        {
            var data = new QueryData();
            data.Id = querySchema[KnownInvokeArgs.QueryId];
            data.QueryState = QueryExecutionState.Queued;
            data.Started = DateTime.Now;
            data.Description = querySchema[KnownInvokeArgs.Query];
            data.CommandId = querySchema.CommandId;
            data.CommandIdDescriptor = CreateCommandIdDescription(querySchema);

            string dataSourceId = querySchema[KnownInvokeArgs.DataSourceId];
            if (!string.IsNullOrEmpty(dataSourceId))
            {
                var exe = App.CurrentApp.GetService<IExecutionContext>();
                if (exe != null)
                {
                    var ds = exe.GetNamedObject(App.CurrentApp.Binder.DefaultContext, dataSourceId) as BrickDataSource;
                    if (ds != null)
                    {
                        data.QueryName = ds.Query.Title;
                    }
                }
            }

            return data;
        }

        static string CreateCommandIdDescription(InvokeSchema schema)
        {
            var sb = new StringBuilder();

            foreach (var arg in schema.Args)
            {
                if (sb.Length > 0)
                {
                    sb.Append(Environment.NewLine);
                }
                sb.Append(arg.Name);
                sb.Append(": ");
                if (arg.Value != null)
                {
                    var val = arg.Value;
                    if (val.Length > 100)
                    {
                        val = val.Substring(0, 100) + "...";
                    }
                    val = val.Replace(Environment.NewLine, " ");
                    sb.Append(val);
                }
            }

            return sb.ToString();
        }

        static void ProcessQueriesFromClient(InvokeSchema querySchema)
        {
            if (!App.CurrentApp.Binder.UserSettings.Settings.EnableLogging) return;

            if (querySchema.CommandId == Galaktika.BI.Silverlight.Commands.CommandId.GetDataCommandId ||
                querySchema.CommandId == Galaktika.BI.Silverlight.Commands.CommandId.UpdateCubeCommandId ||
                querySchema.CommandId == Galaktika.BI.Silverlight.Commands.CommandId.RollbackTransactionCommandId ||
                querySchema.CommandId == Galaktika.BI.Silverlight.Commands.CommandId.CommitTransactionCommandId)
            {
                var id = querySchema[KnownInvokeArgs.QueryId];
                if (!string.IsNullOrEmpty(id))
                {
                    AppendQueryCommand(id, querySchema);
                }
            }
        }

        static void ProcessQueriesFromServer(InvokeResultSchema resultSchema, InvokeSchema schema)
        {
            if (!App.CurrentApp.Binder.UserSettings.Settings.EnableLogging) return;

            if (resultSchema.Queries != null)
            {
                Deployment.Current.Dispatcher.BeginInvoke(() =>
                    {
                        // Обновляем состояние всех запросов
                        var idsFromServer = new List<string>();
                        foreach (var query in resultSchema.Queries)
                        {
                            idsFromServer.Add(query.Id);
                            var qd = vm[query.Id];
                            if (qd != null)
                            {
                                qd.QueryState = query.State;
                                qd.ExecutionTime = (DateTime.Now - qd.Started).ToString();
                                if (qd.QueryState == QueryExecutionState.Done)
                                {
                                    qd.ResponseSize = GetFormattedSize(resultSchema.Content.Length);
                                }
                            }
                        }

                        // Ищем потерянные запросы
                        foreach (QueryData qd in vm)
                        {
                            if (qd.QueryState == QueryExecutionState.Executing &&
                                !idsFromServer.Contains(qd.Id))
                            {
                                qd.QueryState = QueryExecutionState.Lost;
                            }
                        }

                        if (resultSchema.ContentType == KnownContentTypes.Error ||
                            resultSchema.ContentType == KnownContentTypes.ADOMDError)
                        {
                            var queryId = schema[KnownInvokeArgs.QueryId];
                            if (!string.IsNullOrEmpty(queryId))
                            {
                                var qd = vm[queryId];
                                if (qd != null)
                                {
                                    qd.ExecutionTime = (DateTime.Now - qd.Started).ToString();
                                    qd.QueryState = QueryExecutionState.Error;
                                    qd.ErrorText = resultSchema.Content;
                                    qd.ResponseSize = GetFormattedSize(resultSchema.Content.Length);
                                }
                            }
                        }
                    });
            }
        }

        static string GetFormattedSize(int size)
        {
            if (size >= 1024 * 1024) // Mb
            {
                var formatedSize = (size * 10) >> 20;
                return string.Format("{0}{3}{1} {2}", 
                    formatedSize / 10, 
                    formatedSize % 10, 
                    QueryExecutionViewerLocalization.Str_Mb,
                    System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
            }
            if (size >= 1024) // Kb
            {
                var formatedSize = (size * 10) >> 10;
                return string.Format("{0}{3}{1} {2}", 
                    formatedSize / 10, 
                    formatedSize % 10, 
                    QueryExecutionViewerLocalization.Str_Kb,
                    System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
            }

            // bytes
            return string.Format("{0} {1}", size, QueryExecutionViewerLocalization.Str_Bytes);
        }
    }
}
